package qmlt.learning.bagging;

import java.util.ArrayList;
import java.util.List;

import qmlt.dataset.Attribute;
import qmlt.dataset.DataSetBase;
import qmlt.dataset.DataSet;
import qmlt.dataset.DataSetDef;
import qmlt.dataset.Instance;
import qmlt.dataset.utils.ListUtils;
import qmlt.learning.Learner;

@SuppressWarnings("unchecked")
public class Bagging implements Learner<BaggingController>
{

	private List<DataSet>	dataSets	= new ArrayList<DataSet>();

	private List<Learner>	learners	= new ArrayList<Learner>();

	@Override
	public void train(DataSet trainSet, BaggingController params)
	{
		int n = params.getNReplicates();
		int m = trainSet.getInstances().size() * params.getReplicateSizePercentage() / 100;

		for (int i = 0; i < n; ++i)
		{
			DataSet ds = sampleWithReplacement(trainSet, trainSet.getId() + "-sub" + i, m);
			Learner l = params.getBaggedLearnerInstance();
			l.train(ds, params.getBaggedLearnerParams());

			dataSets.add(ds);
			learners.add(l);
		}
	}

	@Override
	public Object predict(Instance instance)
	{
		int n = learners.size();

		List<Object> preds = new ArrayList<Object>();
		for (int i = 0; i < n; ++i)
		{
			Learner l = learners.get(i);
			Object pred = l.predict(instance);
			preds.add(pred);
		}

		if (instance.dataSet.getTargetDef().type.equals(Attribute.STRING)) // classification
		{
			return ListUtils.findMajor(preds);
		}
		else
		// regression
		{
			List<Number> preds0 = ListUtils.convert(preds);
			return ListUtils.mean(preds0);
		}
	}

	private DataSet sampleWithReplacement(DataSet dataSet, String id, int count)
	{
		DataSetDef newDef = new DataSetDef(id, dataSet.getFeatureDefs(), dataSet.getTargetDef());
		DataSet ds = new DataSetBase(newDef, dataSet);
		int n = dataSet.getInstances().size();
		for (int i = 0; i < count; ++i)
		{
			int k = (int) (Math.random() * n);
			ds.getInstances().add(dataSet.getInstances().get(k));
		}
		return ds;
	}

	@Override
	public void loadModel(String inputFilepath)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void saveModel(String outputFilepath)
	{
		// TODO Auto-generated method stub

	}

}
